package com.jcl.recruit.elasticsearch.core.config;

import com.jcl.core.utils.CollectionUtils;
import com.jcl.recruit.elasticsearch.core.utils.ElasticConfigUtils;
import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.message.BasicHeader;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @ClassName ElasticsearchConfig

 * @Author yyliu
 * @Date 2018/11/1 16:31
 * @Version 1.0
 **/
@Configuration
@PropertySource(value = "classpath:elasticsearch.properties")
public class ElasticsearchConfig {

    private static final Logger logger = LoggerFactory.getLogger(ElasticsearchConfig.class);

    @Value("${elastic.config.host_port}")
    private String  hostPort;
    @Value("${elastic.config.index}")
    private String  index;
    @Value("${elastic.config.type}")
    private String  type;
    @Value("${elastic.config.max_retry_timeout_millis}")
    private Integer maxRetryTimeoutMillis;
    @Value("${elastic.config.open_req_header}")
    private Boolean openReqHeader = false;
    @Value("${elastic.config.open_listener}")
    private Boolean openListener = false;
    @Value("${elastic.config.request_config_callback}")
    private Boolean requestConfigCallback = false;
    @Value("${elastic.config.http_client_config_callback}")
    private Boolean httpClientConfigCallback = false;

    @Bean
    public RestClient restClient(){

        ElasticConfigUtils.initHostPort(hostPort);
        ElasticConfigUtils.initEndpoint(index, type);

        List<HttpHost> httpHostList = new ArrayList<>();


        Map<String, List<Integer>> hosts = ElasticConfigUtils.getHostPortMap();
        for(Map.Entry<String, List<Integer>> entry: hosts.entrySet()){
            String host = entry.getKey();
            for(Integer port: entry.getValue()){
                httpHostList.add(new HttpHost(host, port, ElasticConfigUtils.ES_SCHEME));
            }
        }
        if(CollectionUtils.isNotEmpty(httpHostList)){
            HttpHost[] httpHosts = new HttpHost[]{};
            RestClientBuilder builder = RestClient.builder(httpHostList.toArray(httpHosts));
            // setting header
            // (1)设置默认的请求头，以免在每次请求时都指定。设置后每次请求都会带有该请求头
            if(openReqHeader){
                Header[] defaultHeaders = new Header[]{new BasicHeader("header","value")};
                builder.setDefaultHeaders(defaultHeaders);
            }

            // (2) 最好设置一个超时时间以免对同一个请求尝试重试多次。默认的值是30秒，和socket默认的超时时间是一样的。
            // 万一socket的超时时间被自定义了，最大重试超时应相应调整。
            if(null != maxRetryTimeoutMillis){
                builder.setMaxRetryTimeoutMillis(maxRetryTimeoutMillis);
            }

            // (3) 设置一个监听器，当每次节点出现问题时得到提醒，执行方法做一些必要的处理。需要开启失败探测功能。
            if(openListener){
                builder.setFailureListener( new RestClient.FailureListener(){
                    @Override
                    public void onFailure(HttpHost node) {
                        super.onFailure(node);
                        onFailureStart(node);
                    }
                });
            }

            // (4) 设置一个callback来修改默认的请求配置（例如：请求超时时间，身份认证信息，
            // 或者任何可以在org.apache.http.client.config.RequestConfig.Builder中设置的项）
            if(requestConfigCallback){
                builder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
                    @Override
                    public RequestConfig.Builder customizeRequestConfig(RequestConfig.Builder requestConfigBuilder) {
                        requestConfigBuilder.setSocketTimeout(10000);
                        return requestConfigBuilder;
                    }
                });
            }

            // (5) 设置一个callback来修改http client配置（例如：基于SSL的加密通信，
            // 或者任何org.apache.http.impl.nio.client.HttpAsyncClientBuilder运行设置的项）
            if(httpClientConfigCallback){
                builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() {
                    @Override
                    public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpAsyncClientBuilder) {
                        httpAsyncClientBuilder.setProxy(new HttpHost("proxy",9000, ElasticConfigUtils.ES_SCHEME));
                        return httpAsyncClientBuilder;
                    }
                });
            }
            return builder.build();
        }

        return null;
    }

    /** @MethodName onFailureStart
     * //TODO
     * @Param [host]
     * @Return void
     * @Author 63404
     * @Date 2018/11/1
     **/
    public void onFailureStart(HttpHost node){
        logger.info(" RestClient.FailureListener ....");


        logger.info(" RestClient.FailureListener ....");
    }

    public String getHostPort() {
        return hostPort;
    }

    public void setHostPort(String hostPort) {
        this.hostPort = hostPort;
    }

    public String getIndex() {
        return index;
    }

    public void setIndex(String index) {
        this.index = index;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Integer getMaxRetryTimeoutMillis() {
        return maxRetryTimeoutMillis;
    }

    public void setMaxRetryTimeoutMillis(Integer maxRetryTimeoutMillis) {
        this.maxRetryTimeoutMillis = maxRetryTimeoutMillis;
    }

    public Boolean getOpenReqHeader() {
        return openReqHeader;
    }

    public void setOpenReqHeader(Boolean openReqHeader) {
        this.openReqHeader = openReqHeader;
    }

    public Boolean getOpenListener() {
        return openListener;
    }

    public void setOpenListener(Boolean openListener) {
        this.openListener = openListener;
    }

    public Boolean getRequestConfigCallback() {
        return requestConfigCallback;
    }

    public void setRequestConfigCallback(Boolean requestConfigCallback) {
        this.requestConfigCallback = requestConfigCallback;
    }

    public Boolean getHttpClientConfigCallback() {
        return httpClientConfigCallback;
    }

    public void setHttpClientConfigCallback(Boolean httpClientConfigCallback) {
        this.httpClientConfigCallback = httpClientConfigCallback;
    }
}
